package com.wxl.util;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.DisposableBean;
import javax.annotation.PostConstruct;

/**
 * ​​核心特性​​：
 * ​​自动ID分配​​：通过ZooKeeper顺序节点实现自增序号
 * ​​允许重复​​：通过取模运算允许不同节点获得相同ID  0-31
 * ​​自动清理​​：使用临时节点特性自动删除注册信息
 * ​​无需维护池​​：动态生成ID无需预分配
 */
@Slf4j
public class ZkWorkerIdManager implements DisposableBean {
    private static final String SEQUENCE_PATH = "/snowflake/sequence";

    private final CuratorFramework client;
    private volatile String sequenceNodePath;
    private String ipPort;
    private volatile int workerId = -1;

    public ZkWorkerIdManager(CuratorFramework client,String ipPort) {
        this.client = client;
        this.ipPort = ipPort;
    }

    @PostConstruct
    public void init() throws Exception {
        initializeSequencePath();
        registerWorker();
        setupConnectionListener();
    }

    /**
     * 初始化顺序节点路径
     */
    private void initializeSequencePath() throws Exception {
        if (client.checkExists().forPath(SEQUENCE_PATH) == null) {
            try {
                client.create()
                        .creatingParentsIfNeeded()
                        .withMode(CreateMode.PERSISTENT)
                        .forPath(SEQUENCE_PATH);
            } catch (Exception e) {
                log.warn("初始化顺序节点路径失败（可能其他节点已创建）");
            }
        }
    }

    /**
     * 注册Worker节点
     */
    @SneakyThrows
    private void registerWorker() {
        // 创建临时顺序节点（示例路径：/snowflake/sequence/192.168.1.1:8080:seq0000000012）
        sequenceNodePath = client.create()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .forPath(SEQUENCE_PATH + "/"+ipPort+":seq");

        // 解析顺序号（从路径末尾提取数字）
        String sequenceNumber = sequenceNodePath.replaceAll(".*?seq(\\d+)$", "$1");
        long sequence = Long.parseLong(sequenceNumber);

        // 计算Worker ID（0-31）
        workerId = (int) (sequence % 32);
        log.info("注册成功 Worker ID={} (sequence={})", workerId, sequence);
    }

    /**
     * 设置连接监听
     */
    private void setupConnectionListener() {
        client.getConnectionStateListenable().addListener((cli, newState) -> {
            if (newState == ConnectionState.RECONNECTED) {
                handleReconnection();
            }
        });
    }

    /**
     * 处理ZooKeeper重连
     */
    @SneakyThrows
    private void handleReconnection() {
        log.warn("检测到ZooKeeper连接恢复，重新注册Worker...");
        if (sequenceNodePath != null) {
            client.delete().forPath(sequenceNodePath);
        }
        workerId = -1;
        registerWorker();
    }

    /**
     * 获取Worker ID
     */
    public int getWorkerId() {
        if (workerId == -1) {
            throw new IllegalStateException("Worker ID尚未初始化");
        }
        return workerId;
    }

    /**
     * 销毁时清理资源
     */
    @Override
    @SneakyThrows
    public void destroy() {
        if (sequenceNodePath != null) {
            client.delete().forPath(sequenceNodePath);
            log.info("释放Worker资源 ID={}", workerId);
        }
    }
}